package com.imu.purse.modules.trade.service.impl;

import com.alibaba.fastjson.JSON;
import com.github.pagehelper.PageHelper;
import com.google.common.collect.Lists;
import com.imu.common.exception.ErrorDesc;
import com.imu.common.exception.RRException;
import com.imu.constant.Constant;
import com.imu.core.base.BaseService;
import com.imu.core.redis.annotation.RedisLock;
import com.imu.enums.TradeType;
import com.imu.purse.modules.app.dao.CoreMapper;
import com.imu.purse.modules.app.entity.CoreEntity;
import com.imu.purse.modules.bitcoin.YtfcoinApi;
import com.imu.purse.modules.trade.dao.FundMapper;
import com.imu.purse.modules.trade.entity.FundEntity;
import com.imu.purse.modules.trade.entity.FundMergeDetailEntity;
import com.imu.purse.modules.trade.entity.TradeInfoEntity;
import com.imu.purse.modules.trade.service.FundService;
import com.imu.purse.modules.trade.service.TradeInfoService;
import com.imu.utils.IDUtils;
import com.imu.utils.ShortUUID;
import com.xiaoleilu.hutool.util.ArrayUtil;
import com.xiaoleilu.hutool.util.NumberUtil;
import com.xiaoleilu.hutool.util.StrUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Random;

/**
 * 
 * @author sunhongwei
 * @email sunhongwei@jshijian.com
 * @date 2018-03-31 12:04:14
 * Copyright (c) 2017 武汉极时间科技有限公司 版权所有 
 * Jshijian aloha CO.,LTD. All Rights Reserved. 
 */
@Service
public class FundServiceImpl extends BaseService<FundEntity> implements FundService 
{
	@Override
    @Transactional
    public int save(final FundEntity fund)
	{
		fund.setTimeCreate(new Date());
    	fund.setTimeUpdate(new Date());
    	return super.insert(fund);
	}
	
	@Override
	@Transactional
    public int update(final FundEntity fund) 
    {
    	fund.setTimeUpdate(new Date());
    	return mapper.updateByPrimaryKeySelective(fund);
    }
	
	@Override
	@Transactional
	@RedisLock(keys = "#key", expire = 30000, tryTimeout = 1000)
	public void release(final String key, final FundEntity fund)
	{
		if(StrUtil.isBlank(key) || null == fund || null == fund.getUserId() || null == fund.getYtfType()) 
 		{
 			throw new RRException(ErrorDesc.PARAM_EMPTY.getMsg(), ErrorDesc.PARAM_EMPTY.getCode());
 		}
		FundEntity entity = this.findByUserId(fund.getUserId());
		if(null == entity || null == entity.getUserId()) throw new RRException("收款账户不存在，请核实", 6001);

		FundEntity dto = null;
		TradeInfoEntity tradeInfoEntity = null;
 		switch (fund.getYtfType().intValue()) // 0俱乐部, 1交易员
 		{
	 		case 0://降级俱乐部
	 	        if(null == entity.getHbc() || 0 >= entity.getHbc().longValue()) {
	 	        	throw new RRException(ErrorDesc.CLUB_NORMAL.getMsg(), ErrorDesc.CLUB_NORMAL.getCode());
	 	        }
	 	        dto = new FundEntity();
	 			dto.setUserId(fund.getUserId());
	 			dto.setMoney(entity.getHbc());
	 			dto.setHbc(entity.getHbc().multiply(new BigDecimal(-1)));
	 			dto.setTimeUpdate(new Date());
	 			mapper.upPri(dto);
	 			//保存IMU流水记录
	 			tradeInfoEntity = new TradeInfoEntity();
	 			tradeInfoEntity.setPayUserId(fund.getUserId());
	 			tradeInfoEntity.setRecUserId(fund.getUserId());
	 			tradeInfoEntity.setOrderNo(IDUtils.getOrder());
	 			tradeInfoEntity.setMoney(entity.getHbc());
	 			tradeInfoEntity.setSmoney(entity.getMoney());
	 			tradeInfoEntity.setEmoney(entity.getMoney().add(entity.getHbc()));
	 			tradeInfoEntity.setOrderType(2);	//转入
	 			tradeInfoEntity.setOrderState(1);	//成功
	 			tradeInfoEntity.setPayType(-1); 	//系统充值
	 			tradeInfoEntity.setYtfType(TradeType.IMU.getType());	//IMU
	 			tradeInfoEntity.setOrderCreate(new Date());
	 			tradeInfoService.save(tradeInfoEntity);
	 			//扣减HBB 保存流水记录
	 			tradeInfoEntity.setId(null);
	 			tradeInfoEntity.setMoney(entity.getHbc());
	 			tradeInfoEntity.setSmoney(entity.getHbc());
	 			tradeInfoEntity.setEmoney(new BigDecimal("0"));
	 			tradeInfoEntity.setOrderType(0);
	 			tradeInfoEntity.setYtfType(TradeType.HBC.getType());
	 	        tradeInfoService.save(tradeInfoEntity);
				break;
			case 1://取消交易员
				if(null == entity.getBtc() || 0 >= entity.getBtc().longValue()) {
	 	        	throw new RRException(ErrorDesc.BTC_NORMAL.getMsg(), ErrorDesc.BTC_NORMAL.getCode());
	 	        }
				BigDecimal money = entity.getBtc().multiply(new BigDecimal(0.5));//IMU
				BigDecimal get   = entity.getBtc().subtract(money);//GET
	 	        dto = new FundEntity();
	 			dto.setUserId(fund.getUserId());
	 			dto.setMoney(money);	//IMU
	 			dto.setLocketh(get); 	//GET
	 			dto.setBtc(entity.getBtc().multiply(new BigDecimal(-1)));
	 			dto.setTimeUpdate(new Date());
	 			mapper.upPri(dto);
	 			//保存IMU流水记录
	 			tradeInfoEntity = new TradeInfoEntity();
	 			tradeInfoEntity.setPayUserId(fund.getUserId());
	 			tradeInfoEntity.setRecUserId(fund.getUserId());
	 			tradeInfoEntity.setOrderNo(IDUtils.getOrder());
	 			tradeInfoEntity.setMoney(money);
	 			tradeInfoEntity.setSmoney(entity.getMoney());
	 			tradeInfoEntity.setEmoney(entity.getMoney().add(money));
	 			tradeInfoEntity.setOrderType(2);	//转入
	 			tradeInfoEntity.setOrderState(1);	//成功
	 			tradeInfoEntity.setPayType(-1); 	//系统充值
	 			tradeInfoEntity.setYtfType(TradeType.IMU.getType());		//IMU
	 			tradeInfoEntity.setOrderCreate(new Date());
	 			tradeInfoService.save(tradeInfoEntity);
	 			//增加GET 保存流水记录
	 			tradeInfoEntity.setId(null);
	 			tradeInfoEntity.setMoney(get);
	 			tradeInfoEntity.setSmoney(entity.getLocketh());
	 			tradeInfoEntity.setEmoney(entity.getLocketh().add(get));
	 			tradeInfoEntity.setYtfType(TradeType.LK_ETH.getType());	//GET
	 			tradeInfoEntity.setOrderCreate(new Date());
	 			tradeInfoService.save(tradeInfoEntity);
	 			//扣减BTC 保存流水记录
	 			tradeInfoEntity.setId(null);
	 			tradeInfoEntity.setMoney(entity.getBtc());
	 			tradeInfoEntity.setSmoney(entity.getBtc());
	 			tradeInfoEntity.setEmoney(new BigDecimal("0"));
	 			tradeInfoEntity.setOrderType(0);
	 			tradeInfoEntity.setYtfType(TradeType.BTC.getType());
	 	        tradeInfoService.save(tradeInfoEntity);
				break;
			default:
				throw new RRException("类型有误,请核实.", 1120);
 		}
	}

	@Override
	@Transactional
	@RedisLock(keys = "#key", expire = 30000, tryTimeout = 1000)
	public int updateMoney(final String key, final Long userId, final FundEntity fund) 
	{
 		if(StrUtil.isBlank(key) || null == userId || null == fund || null == fund.getUserId() || null == fund.getYtfType()) 
 		{
 			throw new RRException(ErrorDesc.PARAM_EMPTY.getMsg(), ErrorDesc.PARAM_EMPTY.getCode());
 		}
		FundEntity entity = this.findByUserId(fund.getUserId());
 		if(null == entity || null == entity.getUserId()) throw new RRException("收款账户不存在，请核实", 6001);
 		FundEntity useEntity = this.findByUserId(userId);
 		if(null == useEntity || null == useEntity.getBj()) throw new RRException("付款账户不存在，请联系管理员", 6002);
 		BigDecimal smoney  = new BigDecimal("0");//用户开始余额
 		BigDecimal emoney  = new BigDecimal("0");//交易结束金额
 		BigDecimal _smoney = new BigDecimal("0");//系统用户交易开始金额
 		BigDecimal _emoney = new BigDecimal("0");//系统用户交易结束金额
 		
 		switch (fund.getYtfType().intValue()) //com.imu.enums.TradeType
 		{
			case 0:
				smoney  = (null == entity.getMoney()) ? new BigDecimal("0") : entity.getMoney();
				emoney  = (null == entity.getMoney()) ? new BigDecimal("0").add(fund.getMoney()) : entity.getMoney().add(fund.getMoney());
				_smoney = (null == useEntity.getMoney()) ? new BigDecimal("0") : useEntity.getMoney();
				_emoney = (null == useEntity.getMoney()) ? new BigDecimal("0").subtract(fund.getMoney()) : useEntity.getMoney().subtract(fund.getMoney());
				break;
			case 2:
				smoney  = (null == entity.getBj()) ? new BigDecimal("0") : entity.getBj();
				emoney  = (null == entity.getBj()) ? new BigDecimal("0").add(fund.getMoney()) : entity.getBj().add(fund.getMoney());
				_smoney = (null == useEntity.getBj()) ? new BigDecimal("0") : useEntity.getBj();
				_emoney = (null == useEntity.getBj()) ? new BigDecimal("0").subtract(fund.getMoney()) : useEntity.getBj().subtract(fund.getMoney());
				break;
			case 3:
				smoney  = (null == entity.getIco()) ? new BigDecimal("0") : entity.getIco();
				emoney  = (null == entity.getIco()) ? new BigDecimal("0").add(fund.getMoney()) : entity.getIco().add(fund.getMoney());
				_smoney = (null == useEntity.getIco()) ? new BigDecimal("0") : useEntity.getIco();
				_emoney = (null == useEntity.getIco()) ? new BigDecimal("0").subtract(fund.getMoney()) : useEntity.getIco().subtract(fund.getMoney());
				break;
			case 4:
				smoney  = (null == entity.getLocketh()) ? new BigDecimal("0") : entity.getLocketh();
				emoney  = (null == entity.getLocketh()) ? new BigDecimal("0").add(fund.getMoney()) : entity.getLocketh().add(fund.getMoney());
				_smoney = (null == useEntity.getLocketh()) ? new BigDecimal("0") : useEntity.getLocketh();
				_emoney = (null == useEntity.getLocketh()) ? new BigDecimal("0").subtract(fund.getMoney()) : useEntity.getLocketh().subtract(fund.getMoney());
				break;
			case 5:
				smoney  = (null == entity.getLockcowry()) ? new BigDecimal("0") : entity.getLockcowry();
				emoney  = (null == entity.getLockcowry()) ? new BigDecimal("0").add(fund.getMoney()) : entity.getLockcowry().add(fund.getMoney());
				_smoney = (null == useEntity.getLockcowry()) ? new BigDecimal("0") : useEntity.getLocketh();
				_emoney = (null == useEntity.getLockcowry()) ? new BigDecimal("0").subtract(fund.getMoney()) : useEntity.getLockcowry().subtract(fund.getMoney());
				break;
			case 11:
				smoney  = (null == entity.getLockbj()) ? new BigDecimal("0") : entity.getLockbj();
				emoney  = (null == entity.getLockbj()) ? new BigDecimal("0").add(fund.getMoney()) : entity.getLockbj().add(fund.getMoney());
				_smoney = (null == useEntity.getLockbj()) ? new BigDecimal("0") : useEntity.getLockbj();
				_emoney = (null == useEntity.getLockbj()) ? new BigDecimal("0").subtract(fund.getMoney()) : useEntity.getLockbj().subtract(fund.getMoney());
				break;
			case 12:
				smoney  = (null == entity.getLockMoney()) ? new BigDecimal("0") : entity.getLockMoney();
				emoney  = (null == entity.getLockMoney()) ? new BigDecimal("0").add(fund.getMoney()) : entity.getLockMoney().add(fund.getMoney());
				_smoney = (null == useEntity.getLockMoney()) ? new BigDecimal("0") : useEntity.getLockMoney();
				_emoney = (null == useEntity.getLockMoney()) ? new BigDecimal("0").subtract(fund.getMoney()) : useEntity.getLockMoney().subtract(fund.getMoney());
				break;
			case 14:
				smoney  = (null == entity.getLockico()) ? new BigDecimal("0") : entity.getLockico();
				emoney  = (null == entity.getLockico()) ? new BigDecimal("0").add(fund.getMoney()) : entity.getLockico().add(fund.getMoney());
				_smoney = (null == useEntity.getLockico()) ? new BigDecimal("0") : useEntity.getLockico();
				_emoney = (null == useEntity.getLockico()) ? new BigDecimal("0").subtract(fund.getMoney()) : useEntity.getLockico().subtract(fund.getMoney());
				break;
			case 15:
				smoney  = (null == entity.getEth()) ? new BigDecimal("0") : entity.getEth();
				emoney  = (null == entity.getEth()) ? new BigDecimal("0").add(fund.getMoney()) : entity.getEth().add(fund.getMoney());
				_smoney = (null == useEntity.getEth()) ? new BigDecimal("0") : useEntity.getEth();
				_emoney = (null == useEntity.getEth()) ? new BigDecimal("0").subtract(fund.getMoney()) : useEntity.getEth().subtract(fund.getMoney());
				break;
			case 16:
				smoney  = (null == entity.getCowry()) ? new BigDecimal("0") : entity.getCowry();
				emoney  = (null == entity.getCowry()) ? new BigDecimal("0").add(fund.getMoney()) : entity.getCowry().add(fund.getMoney());
				_smoney = (null == useEntity.getCowry()) ? new BigDecimal("0") : useEntity.getCowry();
				_emoney = (null == useEntity.getCowry()) ? new BigDecimal("0").subtract(fund.getMoney()) : useEntity.getCowry().subtract(fund.getMoney());
				break;
			default:
				throw new RRException("交易类型有误,请核实.", 1120);
		}
 		
 		FundEntity dto = new FundEntity();
		dto.setUserId(fund.getUserId());
		dto.setMoney(fund.getMoney());
		dto.setYtfType(fund.getYtfType());
		dto.setTimeUpdate(new Date());
		mapper.up(dto);
		dto = new FundEntity();
		dto.setUserId(userId.longValue());
		dto.setYtfType(fund.getYtfType());
		dto.setMoney(fund.getMoney().multiply(new BigDecimal(-1)));
		dto.setTimeUpdate(new Date());
		mapper.up(dto);
 		
		//插入交易流水记录
		String oid = IDUtils.getOrder();
		TradeInfoEntity tradeInfoEntity = new TradeInfoEntity();
		tradeInfoEntity.setPayUserId(fund.getUserId());
		tradeInfoEntity.setRecUserId(userId);
		tradeInfoEntity.setOrderNo(oid);
		tradeInfoEntity.setMoney(fund.getMoney().abs());
		tradeInfoEntity.setSmoney(smoney);
		tradeInfoEntity.setEmoney(emoney);
		tradeInfoEntity.setDetail(fund.getRemark());
		tradeInfoEntity.setOrderType(-1 == fund.getMoney().compareTo(new BigDecimal(0)) ? 0 : 2);
		tradeInfoEntity.setOrderState(1);
		tradeInfoEntity.setPayType(-1); //系统充值
		tradeInfoEntity.setYtfType(fund.getYtfType());
		tradeInfoEntity.setOrderCreate(new Date());
		tradeInfoService.save(tradeInfoEntity);
        tradeInfoEntity.setId(null);
        tradeInfoEntity.setPayUserId(userId);
        tradeInfoEntity.setRecUserId(fund.getUserId());
        tradeInfoEntity.setMoney(fund.getMoney().abs());
		tradeInfoEntity.setSmoney(_smoney);
		tradeInfoEntity.setEmoney(_emoney);
        tradeInfoEntity.setOrderType(-1 == fund.getMoney().compareTo(new BigDecimal(0)) ? 2 : 0);
        tradeInfoEntity.setYtfType(fund.getYtfType());
		tradeInfoEntity.setOrderCreate(new Date());
        tradeInfoService.save(tradeInfoEntity);
		return 1;
	}

	@Override
	@Transactional
    public int saveUpdate(final FundEntity fund)
    {
    	int len = 0;
    	
    	if(1 > (len = this.update(fund)))
    	{
        	len = this.insert(fund);
    	}
    	
    	return len;
    }
    
 	@Override
	@Transactional
    public boolean delete(final String ...ids)
    {
    	if(ArrayUtil.isEmpty(ids)) return false;
    	
    	for (String id : ids) 
    	{
    		if(StrUtil.isBlank(id)) continue;
    		
    		if(NumberUtil.isNumber(id))
    		{
        		mapper.deleteByPrimaryKey(Long.valueOf(id));
    		}
		}
    	
    	return true;
    }
    
    @Override
    public FundEntity findById(final Long id)
    {
    	if(null == id) return null;
    	return mapper.selectByPrimaryKey(id);
    }
    
    @Override
    public List<FundEntity> queryList(final FundEntity fund)
    {
    	if (fund.getPage() != null && fund.getLimit() != null)
    	{
            PageHelper.startPage(fund.getPage(), fund.getLimit());
        }
    	
    	return mapper.findByPage(fund);
    }
    
    @Override
    public List<FundEntity> queryListOld(final FundEntity fund)
    {
    	if (fund.getPage() != null && fund.getLimit() != null)
    	{
            PageHelper.startPage(fund.getPage(), fund.getLimit());
        }
    	
    	return mapper.findPageOld(fund);
    }
    
    public int upMoney(final FundEntity entity){
    	return mapper.upMoney(entity);
    }

	@Transactional
	public int upBjMoney(final FundEntity entity){
		entity.setTimeUpdate(new Date());
		return mapper.upBjMoney(entity);
	}

    @Override
	public FundEntity findByUserId(Long userId) {
		// TODO Auto-generated method stub
		return mapper.findByUserId(userId);
	}



	public int mergeFund(FundMergeDetailEntity entity){
		entity.setTimeUpdate(new Date());
		mapper.mergeFund(entity);
		return mapper.mergeClearFund(entity);
	}

	/**
	 * 随机选择核心钱包
	 * @return
	 */
	public String  getCoreAddress(){
		//随机获取核心钱包的服务器
		//获取所有的核心钱包的地址
		List<String> coreList = redisTemplate.opsForList().range(Constant.CORE_MONEY_KEY,0,-1);
		if(CollectionUtils.isEmpty(coreList)){
			coreList = Lists.newArrayList();
			List<CoreEntity> entityList = coreMapper.getCoreAddress();
			if(!CollectionUtils.isEmpty(entityList)){
				for(CoreEntity entity : entityList){
					coreList.add(JSON.toJSONString(entity));
					redisTemplate.opsForList().leftPush(Constant.CORE_MONEY_KEY,JSON.toJSONString(entity));
				}
			}
		}
		//随机取一个核心钱包的地址
		Random rand = new Random();
		int curSel = rand.nextInt(coreList.size());
		return coreList.get(curSel);
	}

	public String getCordeByAddress(String address){
		if(StrUtil.isBlank(address)){
			return null;
		}
		Object obj = redisTemplate.opsForHash().get(Constant.CORE_MONEY_USER_KEY,address);
		if(obj == null){
			//2018-07-09 暂时屏蔽,影响性能
			/*FundEntity fundEntity = new FundEntity();
			fundEntity.setMoneyAddress(address);
			fundEntity = mapper.selectOne(fundEntity);
			if(fundEntity != null){
				redisTemplate.opsForHash().put(Constant.CORE_MONEY_USER_KEY,address,fundEntity.getUserId().toString());
				return fundEntity.getUserId().toString();
			}*/
		}else {
			return obj.toString();
		}
		return null;
	}

	public List<FundEntity> findAdressData(final FundEntity fundEntity){
		return mapper.findAdressData(fundEntity);
	}

	public int upAddressById(final FundEntity fundEntity){
		return mapper.upAddressById(fundEntity);
	}

	public FundEntity findByIdAndPhone(final FundEntity fundEntity){
		return mapper.findByIdAndPhone(fundEntity);
	}

	@Autowired
	private FundMapper mapper;

	@Autowired
	private YtfcoinApi ytfcoinApi;

	@Autowired
	private TradeInfoService tradeInfoService;

	@Autowired
	private CoreMapper coreMapper;

	@Autowired
	private RedisTemplate<String,String> redisTemplate;
}
